/*
 * This file is part of the Code::Blocks IDE and licensed under the GNU General Public License, version 3
 * http://www.gnu.org/licenses/gpl-3.0.html
 */

#ifndef NATIVEPARSER_H
#define NATIVEPARSER_H

#include "nativeparser_base.h"
#include "parser/parser.h"

#include <queue>
#include <map>

#include <wx/event.h>

/**
 * debug only variable, used to print the AI match related log message
 * 仅调试变量,用于打印与AI匹配相关的日志消息
 * */
extern bool s_DebugSmartSense;

extern const int g_EditorActivatedDelay;

// forward declaration
//前置声明
class cbEditor;
class EditorBase;
class cbProject;
class cbStyledTextCtrl;
class ClassBrowser;
class Compiler;
class Token;


typedef std::map<cbProject*, wxArrayString> ProjectSearchDirsMap;

// TODO (ollydbg#1#), this class is dirty, I'm going to change its name like CursorLocation
// 这个类是脏的,我要把它的名字改成象CursorLocation样子
/** Search location combination, a pointer to cbStyledTextCtrl and a filename is enough
 * 搜索位置组合,一个指向cbStyledTextCtrl的指针和一个文件名就足够了*/
struct ccSearchData
{
    cbStyledTextCtrl* control;
    wxString          file;
};

/** Symbol browser tree showing option
 * 符号浏览器树显示选项*/
enum BrowserViewMode
{
    bvmRaw = 0,
    bvmInheritance
};

/**
 * 实现功能: NativeParser class is just like a manager class to control Parser objects.
 *
 * Normally, Each C::B Project (cbp) will have an associated Parser object.
 * In another mode, all C::B project belong to a C::B workspace share a single Parser object.
 * Nativeparser will manage all the Parser objects.
 *
 * 实现功能: NativeParser类就像一个管理器类来控制解析器对象.
 * 通常,每个C::B项目(cbp)都有一个相关的解析器对象.
 * 在另一种模式下,属于一个C::B工作区的所有C::B项目共享一个解析器对象.
 * Nativeparser将管理所有解析器对象.
 */
class NativeParser : public wxEvtHandler, NativeParserBase
{
public:
    /** Constructor */
    NativeParser();

    /** Destructor */
    ~NativeParser();

    /** return a reference to the currently active Parser object */
    /** 返回对当前活动解析器对象的引用*/
    ParserBase& GetParser() { return *m_Parser; }

    /**
     * return the Parser pointer corresponding to the input C::B project
     * 参数说明: project input C::B project pointer
     * 返回值:  a pointer to parser object
     *
     * 返回对应于输入C::B项目的解析器指针
     * 参数说明: project 输入C::B项目指针
     * 返回值:  指向解析器对象的指针
     */
    ParserBase* GetParserByProject(cbProject* project);

    /**
     * return the Parser pointer associated with the input file
     * If a file belongs to several Parser objects, the first found Parser will returned.
     * 参数说明: filename filename with full path.
     * 返回值:  Parser pointer
     *
     * 返回与输入文件关联的解析器指针
     * 如果一个文件属于多个解析器对象,则将返回第一个找到的解析器.
     * 参数说明: filename 具有完整路径的文件名.
     * 返回值:  分析器指针
     */
    ParserBase* GetParserByFilename(const wxString& filename);

    /**
     * return the C::B project associated with Parser pointer
     * 参数说明: parser Parser pointer
     * 返回值:  C::B Project pointer
     *
     * 返回与解析器指针关联的C::B项目
     * 参数说明: parser 分析器指针
     * 返回值:  C::B 项目指针
     */
    cbProject* GetProjectByParser(ParserBase* parser);

    /**
     * return the C::B project containing the filename
     * The function first try to match the filename in the active project, next to match other
     * projects opened, If the file exists in several projects, the first matched project will be
     * returned.
     * 参数说明: filename input filename
     * 返回值:  project pointer containing the file
     *
     * 返回包含文件名的C::B项目
     * 函数首先尝试匹配激活项目中的文件名,然后匹配打开的其他项目,如果文件存在于多个项目中,则返回第一个匹配的项目.
     * 参数说明: filename 输入文件名
     * 返回值:  包含文件的项目指针
     */
    cbProject* GetProjectByFilename(const wxString& filename);

    /**
     * return the C::B project containing the cbEditor pointer
     * 参数说明: editor Any valid cbEditor pointer
     * 返回值:  project pointer
     *
     * 返回包含cbEditor(内置编辑器)指针的C::B项目
     * 参数说明: editor 任何有效的cbEditor指针
     * 返回值:  项目指针
     */
    cbProject* GetProjectByEditor(cbEditor* editor);

    /**
     * Get current project by active editor or just return active project
     * 通过活动编辑器获取当前项目或只返回活动项目
     * */
    cbProject* GetCurrentProject();

    /**
     * Return true if use one Parser per whole workspace
     * 如果为true,每个工作区使用一个解析器
     * */
    bool IsParserPerWorkspace() const { return m_ParserPerWorkspace; }

    /**
     * Return true if all the parser's batch-parse stages are finished, otherwise return false
     * 如果解析器的所有批处理分析阶段都已完成,则返回true,否则返回false
     * */
    bool Done();

    /**
     * Used to support Symbol browser and codecompletion UI
     *  Image list is used to initialize the symbol browser tree node image.
     *  用于支持符号浏览器和代码自动补全UI图像列表,用于初始化符号浏览器树节点图像.
     */
    wxImageList* GetImageList() { return m_ImageList; }

    /**
     * Returns the image assigned to a specific token for a symbol browser
     * 返回指定给符号浏览器的特定标记的图像
     * */
    int GetTokenKindImage(const Token* token);

    /**
     * Get the implementation file path if the input is a header file. or Get the header file path
     * if the input is an implementation file.
     * Both the implementation file and header file can be in different directories.
     * 参数说明: filename input filename
     * 返回值:  corresponding file paths, in wxArrayString format
     *
     * 如果输入是头文件,则获取实现文件路径.
     * 如果输入是实现文件,则获取头文件路径.
     * 实现文件和头文件可以在不同的目录中.
     * 参数说明: filename 输入文件名
     * 返回值:  相应的文件路径,采用wxArrayString格式
     */
    wxArrayString GetAllPathsByFilename(const wxString& filename);

    /**
     * Add the paths to path array, and this will be used in GetAllPathsByFilename() function.
     *  internally, all the folder paths were recorded in UNIX format.
     * 参数说明: dirs the target dir collection
     * 参数说明: path the new added path
     * 参数说明: hasExt the file path has extensions, such as C:/aaa/bbb.cpp
     *
     * 将路径添加到path数组,这将在GetAllPathsByFilename()函数中使用.
     * 在内部,所有文件夹路径都以UNIX格式记录.
     * 参数说明: dirs 目标目录集合
     * 参数说明: path 新添加的路径
     * 参数说明: hasExt 文件路径有扩展名,如C:/aaa/bbb.cpp
     */
static void AddPaths(wxArrayString& dirs, const wxString& path, bool hasExt);

    // the functions below are handling and managing Parser object
    // 下面的函数是处理和管理解析器对象

    /**
     * Dynamically allocate a Parser object for the input C::B project, note that while create a
     * new Parser object, the DoFullParsing() function will be called, which collect the macro
     * definitions, and start the batch parsing from the thread pool.
     * 参数说明: project C::B project
     * 返回值:  Parser pointer of the project.
     *
     * 为输入C::B项目动态分配一个解析器对象,请注意,在创建一个新的解析器对象时,将调用DoFullParsing()函数,该函数收集宏定义,并从线程池开始批解析.
     * 参数说明: project C::B项目
     * 返回值:  项目的解释器指针.
     */
    ParserBase* CreateParser(cbProject* project);

    /**
     * delete the Parser object for the input project
     * 参数说明: project C::B project.
     * 返回值:  true if success.
     *
     * 删除输入项目的解析器对象
     * 参数说明: project C::B项目.
     * 返回值:  成功返回真(true).
     */
    bool DeleteParser(cbProject* project);

    /**
     * Single file re-parse.
     * This was happening when you add a single file to project, or a file was modified.
     * the main logic of this function call is:
     * 1, once this function is called, the file will be marked as "need to be reparsed" in the
     *    token tree, and a timer(reparse timer) is started.
     * 2, on reparse timer hit, we collect all the files marked as "need to be reparsed" from the
     *    token tree, remove them from the token tree, and call AddParse() to add parsing job, this
     *    will ticket the On batch timer
     * 3, when on batch timer hit, it see there are some parsing jobs to do (m_BatchParseFiles is
     *    not empty), then it will run a thread job ParserThreadedTask
     * 4, Once the ParserThreadedTask is running, it will create all the Parserthreads and run them
     *    in the thread pool
     * 参数说明: project C::B project
     * 参数说明: filename filename with full path in the C::B project
     *
     * 对单个文件进行重新解释.
     * 当您向项目中添加一个文件或修改了一个文件时,就会发生这种情况.
     * 此函数调用的主要逻辑是:
     * 1, 调用此函数后,文件将在标记树中标记为“需要重新分析”,并启动计时器(重新分析计时器).
     * 2, 在重分析计时器命中时,我们从令牌树中收集所有标记为“需要重新解析”的文件,将它们从令牌树中删除,然后调用AddParse()添加解析作业,这将为批处理计时器提供凭证
     * 3, 当批处理计时器命中时,它看到有一些解析作业要做(m_BatchParseFiles不为空),然后它将运行一个线程(解释线程任务)作业(ParserThreadedTask)
     * 4, 一旦ParserThreadedTask运行,它将创建所有Parserthreads并在线程池中运行它们
     * 参数说明: project C::B项目
     * 参数说明: filename C::B项目中具有完整路径的文件名
     *
     */
    bool ReparseFile(cbProject* project, const wxString& filename);

    /**
     * New file was added to the C::B project, so this will cause a re-parse on the new added file.
     * 参数说明: project C::B project
     * 参数说明: filename filename with full path in the C::B project
     *
     * 新文件已添加到C::B项目中,因此这将导致对新添加的文件进行重新分析.
     * 参数说明: project C::B项目
     * 参数说明: filename C::B项目中具有完整路径的文件名
     *
     */
    bool AddFileToParser(cbProject* project, const wxString& filename, ParserBase* parser = nullptr);

    /**
     * remove a file from C::B project and Parser
     * 参数说明: project C::B project
     * 参数说明: filename filename with full patch in the C::B project
     * 从C::B项目和解析器中删除文件
     * 参数说明: project C::B项目
     * 参数说明: filename C::B项目中具有完整路径的文件名
     */
    bool RemoveFileFromParser(cbProject* project, const wxString& filename);

    /**
     * when user changes the CC option, we should re-read the option
     * 当用户更改代码自动补全选项时,我们应该重新读取该选项
     * */
    void RereadParserOptions();

    /**
     * re-parse the active Parser (the project associated with m_Parser member variable
     * 重新解析活动解析器与m_Parser成员变量关联的项目
     * */
    void ReparseCurrentProject();

    /**
     * re-parse the project select by context menu in projects management panel
     * 重新分析“项目管理”面板中的“按上下文选择项目”菜单
     * */
    void ReparseSelectedProject();

    /**
     * collect tokens where a code suggestion list can be shown
     * @param[in] searchData search location, the place where the caret locates
     * @param[out] result containing all matching result token indexes
     * 参数说明: reallyUseAI true means the context scope information should be considered,
     *        false if only do a plain word match
     * 参数说明: isPrefix partially match which result all the Tokens' name with the same prefix,
              otherwise use full-text match
     * 参数说明: caseSensitive case sensitive or not
     * 参数说明: caretPos Where the current caret locates, -1 means we use the current caret position.
     * 返回值:  the matching Token count
     *
     * 收集可以显示代码建议列表的令牌(标识符)
     * 入口参数 searchData 搜索位置,插入符号所在的位置
     * 出口参数 result 包含所有匹配的结果标记索引
     * 参数说明: reallyUseAI true表示应该考虑上下文范围信息,如果只进行纯词匹配,则为false
     * 参数说明: isPrefix 部分匹配导致所有标记的名称具有相同的前缀,否则使用全文匹配
     * 参数说明: caseSensitive 是否区分大小写
     * 参数说明: caretPos 在当前插入符号所在的位置,-1表示使用当前插入符号位置.
     * 返回值:  匹配的令牌(标识符)数
     *
     */
    size_t MarkItemsByAI(ccSearchData* searchData, TokenIdxSet& result, bool reallyUseAI = true,
                         bool isPrefix = true, bool caseSensitive = false, int caretPos = -1);

    /**
     * the same as before, but we don't specify the searchData information, so it will use the active
     *  editor and current caret information.
     *  与前面相同,但是我们没有指定searchData信息,因此它将使用活动编辑器和当前插入符号信息.
     */
    size_t MarkItemsByAI(TokenIdxSet& result, bool reallyUseAI = true, bool isPrefix = true,
                         bool caseSensitive = false, int caretPos = -1);

    /**
     * Call tips are tips when you are typing function arguments
     * these tips information could be:
     * the prototypes information of the current function,
     * the type information of the variable.
     * Here are the basic algorithm
     *
     * if you have a function declaration like this: int fun(int a, float b, char c);
     * when user are typing code, the caret is located here
     * fun(arg1, arg2|
     *    ^end       ^ begin
     * we first do a backward search, should find the "fun" as the function name
     * and later return the string "int fun(int a, float b, char c)" as the call tip
     * typedCommas is 1, since one argument is already typed.
     *
     * @param[out] items array to store the tip results.
     * 参数说明: typedCommas how much comma characters the user has typed in the current line before the cursor.
     * 参数说明: ed the editor
     * 参数说明: pos the location of the caret, if not supplied, the current caret is used
     * 返回值:  The location in the editor of the beginning of the argument list
     *
     * 调用提示是键入函数参数时的提示这些提示信息可以是:当前函数的原型信息,变量的类型信息.
     * 下面是基本算法:
     *
     * 如果你有这样的函数声明: int fun(int a, float b, char c);
     * 当用户键入代码时,插入符号位于此处
     * fun(arg1, arg2|
     *    ^结束位       ^ 起始位
     * 我们首先进行反向搜索,应该找到“fun”作为函数名,然后返回字符串"int fun(int a, float b, char c)",
     * 因为调用提示typedCommand是1,因为已经输入了一个参数.
     *
     * 出口参数 items 存储提示结果的项数组.
     * 参数说明: typedCommas 用户在光标前面的当前行中键入了多少逗号字符.
     * 参数说明: ed 编辑器
     * 参数说明: pos 插入符号的位置,如果未提供,则使用当前插入符号
     * 返回值:  参数列表开头在编辑器中的位置
     */
    int GetCallTips(wxArrayString& items, int& typedCommas, cbEditor* ed, int pos = wxNOT_FOUND);

    /**
     * project search path is used for auto completion for #include <>
     * 项目搜索路径用于#include <>的自动完成
     * */
    wxArrayString& GetProjectSearchDirs(cbProject* project);

    // The function below is used to manage symbols browser
    // 以下功能用于管理符号浏览器
    /**
     * return active class browser pointer
     * 返回活动类浏览器指针
     * */
    ClassBrowser* GetClassBrowser() const { return m_ClassBrowser; }

    /**
     * create the class browser
     * 创建类浏览器
     * */
    void CreateClassBrowser();

    /**
     * remove the class browser
     * 移除类浏览器
     * */
    void RemoveClassBrowser(bool appShutDown = false);

    /**
     * update the class browser tree
     * 更新类浏览器树
     * */
    void UpdateClassBrowser();

protected:
    /**
     * When a Parser is created, we need a full parsing stage including:
     * 1, parse the priority header files firstly.
     * 2, parse all the other project files.
     *
     * 创建解析器时,我们需要一个完整的解析阶段,包括
     * 1, 首先解析优先级头文件.
     * 2, 解析所有其他项目文件.
     */
    bool DoFullParsing(cbProject* project, ParserBase* parser);

    /**
     * Switch parser object according the current active editor and filename
     * 根据当前活动的编辑器和文件名切换解析器对象
     * */
    bool SwitchParser(cbProject* project, ParserBase* parser);

    /**
     * Set a new Parser as the active Parser
     * Set the active parser pointer (m_Parser member variable)
     * update the ClassBrowser's Parser pointer
     * re-fresh the symbol browser tree.
     * if we did switch the parser, we also need to remove the temporary tokens of the old parser.
     *
     * 将新的解析器设置为活动解析器
     * 设置活动的解析器指针(m_parser成员变量)
     * 更新ClassBrowser的解析器指针
     * 重新刷新符号浏览器树.
     * 如果我们切换了解析器,我们还需要删除旧解析器的临时标记.
     */
    void SetParser(ParserBase* parser);

    /**
     * Clear all Parser object
     * 清除所有解释器对象
     * */
    void ClearParsers();

    /**
     * Remove all the obsolete Parser object
     * if the number exceeds the limited number (can be set in the CC's option), then all the
     * obsolete parser will be removed.
     *
     * 删除所有过时的解析器对象
     * 如果数量超过了限制的数量(可以在CC的选项中设置),那么将删除所有过时的解析器.
     */
    void RemoveObsoleteParsers();

    /**
     * Get cbProject and Parser pointer, according to the current active editor
     * 根据当前活动编辑器,获取cbProject和解析器指针
     * */
    std::pair<cbProject*, ParserBase*> GetParserInfoByCurrentEditor();

    /**
     * Used to support Symbol browser and codecompletion UI
     *  Image list is used to initialize the symbol browser tree node image.
     *  用于支持符号浏览器和代码自动补全UI图像列表,用于初始化符号浏览器树节点图像.
     */
    void SetTokenKindImage(int kind, const wxBitmap& bitmap, const wxBitmap& mask = wxNullBitmap);
    void SetTokenKindImage(int kind, const wxBitmap& bitmap, const wxColour& maskColour);
    void SetTokenKindImage(int kind, const wxIcon& icon);

    /**
     * set the class browser view mode
     * 设置类浏览器视图模式
     * */
    void SetCBViewMode(const BrowserViewMode& mode);

private:
    friend class CodeCompletion;

    /**
     * Read or Write project' CC options when a C::B project is loading or saving
     * user can set those settings in Menu->Project->Properties->C/C++ parser options panel
     * 参数说明: project which project we are handling
     * 参数说明: elem parent node of the project xml file (cbp) containing addtinal information
     * 参数说明: loading true if the project is loading
     *
     * 在C::B项目正在加载或保存时,可以读取或写入项目“CC选项”,用户可以在Menu->Project->Properties->C/C++分析器选项面板设置这些选项
     * 参数说明: project 我们在处理哪个项目
     * 参数说明: elem 包含添加信息的项目xml文件(cbp)的父节点
     * 参数说明: loading 如果项目正在加载,则为true
     */
    void OnProjectLoadingHook(cbProject* project, TiXmlElement* elem, bool loading);

    /**
     * Start an Artificial Intelligence search algorithm to gather all the matching tokens.
     * The actual AI is in FindAIMatches() below.
     * 参数说明: result output parameter.
     * 参数说明: searchData cbEditor information.
     * 参数说明: lineText current statement.
     * 参数说明: isPrefix if true, then the result contains all the tokens whose name is a prefix of current lineText.
     * 参数说明: caseSensitive true is case sensitive is enabled on the match.
     * 参数说明: search_scope it is the "parent token" where we match the "search-key".
     * 参数说明: caretPos use current caret position if it is -1.
     * 返回值:  matched token number
     *
     * 启动一个人工智能搜索算法来收集所有匹配的令牌.
     * 实际的人工智能在下面的FindAIMatches()中.
     * 参数说明: result 输出参数.
     * 参数说明: searchData cbEditor信息.
     * 参数说明: lineText 当前语句.
     * 参数说明: isPrefix 如果为true,则结果包含名称为当前lineText前缀的所有标记.
     * 参数说明: caseSensitive 如果为true,则在匹配项上启用区分大小写.
     * 参数说明: search_scope 它是我们匹配“搜索密钥”的“父令牌”.
     * 参数说明: caretPos 如果当前插入符号位置为-1,则使用它.
     * 返回值:  匹配的令牌号
     */
    size_t AI(TokenIdxSet& result,
              ccSearchData* searchData,
              const wxString& lineText = wxEmptyString,
              bool isPrefix = false,
              bool caseSensitive = false,
              TokenIdxSet* search_scope = 0,
              int caretPos = -1);

    /**
     * return all the tokens matching the current function(hopefully, just one)
     * 参数说明: editor editor pointer
     * 参数说明: result output result containing all the Token index
     * 参数说明: caretPos -1 if the current caret position is used.
     * 返回值:  number of result Tokens
     *
     * 返回与当前函数匹配的所有标记(希望只有一个)
     * 参数说明: editor 编辑器指针
     * 参数说明: result 包含所有令牌索引的输出结果
     * 参数说明: caretPos 如果使用当前插入符号位置,则为-1.
     * 返回值:  结果标记数
     */
    size_t FindCurrentFunctionToken(ccSearchData* searchData, TokenIdxSet& result, int caretPos = -1);

    /**
     * returns the position where the current function scope starts.
     * optionally, returns the function's namespace (ends in double-colon ::), name and token
     * @param[in] searchData search data struct pointer
     * @param[out] nameSpace get the namespace modifier
     * @param[out] procName get the function name
     * @param[out] functionToken get the token of current function
     * 参数说明: caretPos caret position in cbEditor
     * 返回值:  current function line number
     *
     * 返回当前函数作用域开始的位置.
     * 或者,返回函数的命名空间(以双冒号::结尾)、名称和令牌
     * 入口参数 searchData 搜索数据结构指针
     * 出口参数 nameSpace 获取命名空间修饰符
     * 出口参数 procName 获取函数名
     * 出口参数 functionToken 获取当前函数的令牌
     * 参数说明: caretPos cbEditor中的插入符号位置
     * 返回值:  当前功能行号
     */
    int FindCurrentFunctionStart(ccSearchData* searchData,
                                 wxString*     nameSpace = 0L,
                                 wxString*     procName = 0L,
                                 int*          functionIndex = 0L,
                                 int           caretPos = -1);

    /**
     * used in CodeCompletion suggestion list to boost the performance, we use a caches
     * 在代码补全建议列表中使用一个缓存来提高性能
     * */
    bool LastAISearchWasGlobal() const { return m_LastAISearchWasGlobal; }

    /**
     * The same as above
     * 同上
     * */
    const wxString& LastAIGlobalSearch() const { return m_LastAIGlobalSearch; }

    /**
     * collect the using namespace directive in the editor specified by searchData
     * 参数说明: searchData search location
     * 参数说明: search_scope resulting tokens collection
     * 参数说明: caretPos caret position, if not specified, we use the current caret position
     *
     * 在searchData指定的编辑器中收集using namespace指令
     * 参数说明: searchData 搜索位置
     * 参数说明: search_scope 生成的令牌集合(作用域)
     * 参数说明: caretPos 插入符号位置,如果未指定,则使用当前插入符号位置
     */
    bool ParseUsingNamespace(ccSearchData* searchData, TokenIdxSet& search_scope, int caretPos = -1);

    /**
     * collect the using namespace directive in the buffer specified by searchData
     * 参数说明: buffer code to parse
     * 参数说明: search_scope resulting tokens collection
     * 参数说明: bufferSkipBlocks skip brace sets { }
     *
     * 在searchData指定的缓冲区中收集using namespace指令
     * 参数说明: buffer 要分析的代码缓冲区
     * 参数说明: search_scope 生成的令牌集合(作用域)
     * 参数说明: bufferSkipBlocks 跳过大括号集{}
     */
    bool ParseBufferForUsingNamespace(const wxString& buffer, TokenIdxSet& search_scope, bool bufferSkipBlocks = true);

    /**
     * collect function argument, add them to the token tree (as temporary tokens)
     * 参数说明: searchData search location
     * 参数说明: caretPos caret position, if not specified, we use the current caret position
     *
     * 收集函数参数,将它们添加到令牌树中(作为临时标记)
     * 参数说明: searchData 搜索位置
     * 参数说明: caretPos 插入符号位置,如果未指定,则使用当前插入符号位置
     */
    bool ParseFunctionArguments(ccSearchData* searchData, int caretPos = -1);

    /**
     * parses from the start of function up to the cursor, this is used to collect local variables.
     * 参数说明: searchData search location
     * 参数说明: search_scope resulting tokens collection of local using namespace
     * 参数说明: caretPos caret position, if not specified, we use the current caret position
     *
     * 从函数开始一直到光标的解析,这是用来收集局部变量的.
     * 参数说明: searchData 搜索位置
     * 参数说明: search_scope 使用命名空间的本地生成标记集合
     * 参数说明: caretPos插入符号位置,如果未指定,则使用当前插入符号位置
     */
    bool ParseLocalBlock(ccSearchData* searchData, TokenIdxSet& search_scope, int caretPos = -1);

    /**
     * collect the header file search directories, those dirs include:
     *  1, project's base dir, e.g. if you cbp file was c:/bbb/aaa.cbp, then c:/bbb is added.
     *  2, project's setting search dirs, for a wx project, then c:/wxWidgets2.8.12/include is added.
     *  3, a project may has some targets, so add search dirs for those targets
     *  4, compiler's own search path, like: c:/mingw/include
     *
     * 收集头文件搜索目录,这些目录包括:
     *  1, 项目的基本目录,例如,如果您的cbp文件是c:/bbb/aaa.cbp,然后添加c:/bbb.
     *  2, 项目的设置搜索目录(searchdirs),对于wx项目,则添加c:/wxWidgets2.8.12/include.
     *  3, 一个项目可能有一些目标,所以添加这些目标的搜索目录
     *  4, 编译器自己的搜索路径,如：c:/mingw/include
     *  (对于linux系统应该检测系统默认对应的包含文件目录)
     *
     */
    bool AddCompilerDirs(cbProject* project, ParserBase* parser);

    /**
     * collect compiler specific predefined preprocessor definition, this is usually run a special
     * compiler command, like GCC -dM for gcc.
     * 返回值:  true if there are some macro definition added, else it is false
     *
     * 收集编译器特定的预定义预处理器定义(采集预定义宏),这通常是运行一个特殊的编译器命令,如:GCC编译器的GCC -dM.
     * 返回值:  如果添加了一些宏定义,则为true,否则为false
     */
    bool AddCompilerPredefinedMacros(cbProject* project, ParserBase* parser);

    /**
     * collect GCC compiler predefined preprocessor definition
     * 收集GCC编译器预定义的预处理器定义
     * */
    bool AddCompilerPredefinedMacrosGCC(const wxString& compilerId, cbProject* project, wxString& defs, ParserBase* parser);

    /**
     * lookup GCC compiler -std=XXX option
     * 查找GCC编译器-std=XXX选项
     * */
    wxString GetCompilerStandardGCC(Compiler* compiler, cbProject* project);

    /**
     * lookup GCC compiler -std=XXX option for specific GCC options
     * 查找GCC编译器-std=XXX选项以获取特定GCC选项
     * */
    wxString GetCompilerUsingStandardGCC(const wxArrayString& compilerOptions);

    /**
     * collect VC compiler predefined preprocessor definition
     * 收集VC编译器预定义的预处理器定义
     * */
    bool AddCompilerPredefinedMacrosVC(const wxString& compilerId, wxString& defs, ParserBase* parser);

    /**
     * collect project (user) defined preprocessor definition, such as for wxWidgets project, the
     * macro may have "#define wxUSE_UNICODE" defined in its project file.
     * 返回值:  true if there are some macro definition added, else it is false
     *
     * 收集项目(用户)定义的预处理器定义,例如对于wxWidgets项目,宏可能在其项目文件中定义了“#define wxUSE_UNICODE”.
     * 返回值:  如果添加了一些宏定义,则为true,否则为false
     */
    bool AddProjectDefinedMacros(cbProject* project, ParserBase* parser);

    /**
     * Add compiler include directories (from search paths) to a parser
     * 将编译器包含目录(从搜索路径)添加到解析器
     * */
    void AddCompilerIncludeDirsToParser(const Compiler* compiler, ParserBase* parser);

    /**
     * Collect the default compiler include file search paths. called by AddCompilerDirs() function
     * 收集默认编译器包含文件搜索路径.由AddCompilerDirs()函数调用
     * */
    const wxArrayString& GetGCCCompilerDirs(const wxString &cpp_compiler);

    /**
     * Add the collected default GCC compiler include search paths to a parser
     * 将收集到的默认GCC编译器include搜索路径添加到解析器
     * */
    void AddGCCCompilerDirs(const wxString& masterPath, const wxString& compilerCpp, ParserBase* parser);

    /** Add a list of directories to the parser's search directories, normalise to "base" path, if
     * "base" is not empty. Replaces macros.
     *
     * 将目录列表添加到解析器的搜索目录中,如果“base”不为空,则规范化为“base”路径.替换宏.
     */
    void AddIncludeDirsToParser(const wxArrayString& dirs, const wxString& base, ParserBase* parser);

    /**
     * Event handler when the batch parse starts, print some log information
     * 事件处理程序当批处理分析开始时,打印一些日志信息
     * */
    void OnParserStart(wxCommandEvent& event);

    /**
     * Event handler when the batch parse finishes, print some log information, check whether the active editor
     * belong to the current parser, if not, do a parser switch
     * 事件处理程序批解析完成后,打印一些日志信息,检查活动编辑器是否属于当前解析器,如果不属于,则做解析器切换
     */
    void OnParserEnd(wxCommandEvent& event);

    /**
     * If use one parser per whole workspace, we need parse all project one by one, E.g.
     * If a workspace contains A.cbp, B.cbp and C.cbp, and we are in the mode of one parser for
     * the whole workspace, we first parse A.cbp, after that we should continue to parse B.cbp. When
     * finishing parsing B.cbp, we need the timer again to parse the C.cbp.
     * If we are in the mode of one parser for one project, then after parsing A.cbp, the timer is
     * kicked, so there is a chance to parse the B.cbp or C.cbp, but only when user opened some file
     * of B.cbp or C.cbp when the timer event arrived.
     *
     * 如果每个工作区使用一个解析器,我们需要逐个解析所有的项目,例如.
     * 如果一个工作区包含a.cbp、B.cbp和C.cbp,并且我们对整个工作区都是一个解析器,
     * 那么我们首先解析a.cbp,然后再继续解析B.cbp.当完成对B.cbp的解析时,我们需要再次使用计时器来解析C.cbp.
     * 如果我们在一个项目中使用一个解析器的模式,
     * 那么在解析A.cbp之后,计时器将被踢出,
     * 因此有机会解析B.cbp或C.cbp,
     * 但只有当计时器事件到达时,用户才打开B.cbp或C.cbp的某个文件.
     *
     */
    void OnParsingOneByOneTimer(wxTimerEvent& event);

    /**
     * Event handler when an editor activate, *NONE* project is handled here
     * 事件处理程序当编辑器激活时,*NONE*项目在此处处理
     *
     * */
    void OnEditorActivated(EditorBase* editor);

    /** Event handler when an editor closed, if it is the last editor belong to *NONE* project, then
     *  the *NONE* Parser will be removed
     *  事件处理程序当编辑器关闭时,如果它是属于*NONE*项目的最后一个编辑器,则*NONE*解析器将被删除
     */
    void OnEditorClosed(EditorBase* editor);

    /** Init cc search member variables
     * 初始化代码自动补全搜索成员变量*/
    void InitCCSearchVariables();

    /**
     * Add one project to the common parser in one parser for the whole workspace mode
     * 返回值:  true means there are some thing (macro and files) need to parse, otherwise it is false
     * 在一个解析器中为整个工作区模式向公共解析器添加一个项目
     * 返回值:  true表示有一些东西(宏和文件)需要解析,否则为false
     */
    bool AddProjectToParser(cbProject* project);

    /** Remove cbp from the common parser, this only happens in one parser for whole workspace mode
     * when a parser is removed from the workspace, we should remove the project from the parser
     *
     * 当解析器从整个工作区中移除时,我们应该只从一个通用的解析器工作区中删除一个解析器
     */
    bool RemoveProjectFromParser(cbProject* project);

private:
    typedef std::pair<cbProject*, ParserBase*> ProjectParserPair;
    typedef std::list<ProjectParserPair>       ParserList;

    /**
     * a list holing all the cbp->parser pairs, if in one parser per project mode, there are many
     * many pairs in this list. In one parser per workspace mode, there is only one pair, and the
     * m_ParserList.begin()->second is the common parser for all the projects in workspace.
     *一个包含所有cbp->parser对的列表,如果在每个项目的一个解析器模式中,这个列表中有许多对.
     * 在每个工作区一个解析器模式中,只有一对,m_ParserList.begin()->second是工作区中所有项目的通用解析器.
     */
    ParserList                   m_ParserList;
    /**
     * a temp parser object pointer
     * 临时解析器对象指针
     * */
    ParserBase*                  m_TempParser;
    /**
     * active parser object pointer
     * 活动分析器对象指针
     * */
    ParserBase*                  m_Parser;

    /**
     * a delay timer to parser every project in sequence
     * 一个延迟计时器,用于按顺序分析每个项目
     * */
    wxTimer                      m_TimerParsingOneByOne;
    /**
     * symbol browser window
     * 符号浏览器窗口
     * */
    ClassBrowser*                m_ClassBrowser;
    /**
     * if true, which means m_ClassBrowser is floating (not docked)
     * 如果为true,则表示m_ClassBrowser处于浮动状态(未停靠)
     * */
    bool                         m_ClassBrowserIsFloating;

    /**
     * a map: project pointer -> C/C++ parser search paths for this project, this is the
     * per-project code completion search-dirs.
     * 一个图:项目指针 ->C/C++分析器搜索路径,用于这个项目,这是每个项目代码完成搜索目录.
     */
    ProjectSearchDirsMap         m_ProjectSearchDirsMap;
    //!< 项目加载器钩子ID
    int                          m_HookId;
    //!< Images for class browser
    //!< 类浏览器图像
    wxImageList*                 m_ImageList;

    /**
     * all the files which opened, but does not belong to any cbp
     * 所有打开的文件,但不属于任何cbp项目
     * */
    wxArrayString                m_StandaloneFiles;
    /**
     * if true, which means the parser hold tokens of the whole workspace's project, if false
     * then one parser per a cbp
     * 如果为true,则意味着解析器持有整个工作区项目的标记,如果为false,则每个cbp有一个解析器
     */
    bool                         m_ParserPerWorkspace;
    /**
     * only used when m_ParserPerWorkspace is true, and holds all the cbps for the common parser
     * 仅当m_ParserPerWorkspace为true时使用,并保存公共解析器的所有cbp
     * */
    std::set<cbProject*>         m_ParsedProjects;

    /*
     * CC Search Member Variables => START
     * 代码自动补全搜索成员变量=>开始
     * */
    //!< same case like above, it holds the search string
    //!< 和上面一样,它保存了搜索字符串
    wxString          m_LastAIGlobalSearch;
    //!< true if the phrase for code-completion is empty or partial text (i.e. no . -> or :: operators)
    //!< 如果代码完成的短语为空或部分文本(即no.->或::运算符)
    bool              m_LastAISearchWasGlobal;
    cbStyledTextCtrl* m_LastControl;
    wxString          m_LastFile;
    int               m_LastFunctionIndex;
    //!< saved the function token's index, for remove all local variable
    //!< 保存了函数标记的索引,用于删除所有局部变量
    int               m_LastFuncTokenIdx;
    int               m_LastLine;
    wxString          m_LastNamespace;
    wxString          m_LastPROC;
    int               m_LastResult;
    /*
     * CC Search Member Variables => END
     * 代码自动补全搜索成员变量=>结束
     * */

};

#endif // NATIVEPARSER_H

